<?php

namespace common\models;

use common\components\OrderBehavior;
use common\helpers\commonApi;
use common\helpers\TransformApi;
use EasyWeChat\Factory;
use Yii;
use yii\db\Exception;

/**
 * This is the model class for table "{{%order}}".
 *
 * @property int $id
 * @property int|null $userid 用户id
 * @property string|null $order_sn 订单编号
 * @property int|null $order_status 订单状态
 * @property int|null $pay_status 支付状态
 * @property string|null $pay_time 支付时间
 * @property string|null $consignee 收获人
 * @property string|null $province 省份
 * @property string|null $city 城市
 * @property string|null $district 县区
 * @property string|null $address 地址
 * @property string|null $mobile 手机
 * @property float|null $total_amount 总金额
 * @property float|null $pay_amount 支付金额
 * @property float|null $discount_amount 优惠金额
 * @property int|null $total_num 订单商品数量
 * @property int|null $shipping_status 发货状态
 * @property float|null $freight 运费
 * @property string|null $shipping_time 发货时间
 * @property string|null $transaction_id 第三方平台交易流水号
 * @property string|null $user_remark 用户备注
 * @property string|null $confirm_take_time 确认收货时间
 * @property string|null $cancel_time 订单取消时间
 * @property int|null $refund_status 退款状态
 * @property string|null $order_remarks 订单备注
 * @property int|null $del 删除 1-删除 0-未删除
 * @property string|null $create_time 下单时间
 * @property string|null $update_time 修改时间
 * @property string|null $transaction_info 第三方平台信息
 * @property string|null $express_type 快递类型
 * @property string|null $express_sn 快递单号
 * @property string|null $party_order 第三方订单号
 * @property int|null $is_comment 是否评价完
 */
class Order extends BaseModel
{
    /**
     * {@inheritdoc}
     */
    public static function tableName()
    {
        return '{{%order}}';
    }

    /**
     * {@inheritdoc}
     */
    public function rules()
    {
        return [
            [['userid', 'order_status', 'pay_status', 'total_num', 'shipping_status', 'refund_status', 'del', 'is_comment'], 'integer'],
            [['pay_time', 'shipping_time', 'confirm_take_time', 'cancel_time', 'create_time', 'update_time'], 'safe'],
            [['total_amount', 'pay_amount', 'discount_amount', 'freight'], 'number'],
            [['user_remark', 'order_remarks', 'transaction_info'], 'string'],
            [['order_sn', 'consignee', 'province', 'city', 'district', 'address', 'mobile', 'transaction_id', 'express_type', 'express_sn', 'party_order'], 'string', 'max' => 255],
        ];
    }

    /**
     * {@inheritdoc}
     */
    public function attributeLabels()
    {
        return [
            'id' => 'ID',
            'userid' => '用户id',
            'order_sn' => '订单编号',
            'order_status' => '订单状态',
            'pay_status' => '支付状态',
            'pay_time' => '支付时间',
            'consignee' => '收获人',
            'province' => '省份',
            'city' => '城市',
            'district' => '县区',
            'address' => '地址',
            'mobile' => '手机',
            'total_amount' => '总金额',
            'pay_amount' => '支付金额',
            'discount_amount' => '优惠金额',
            'total_num' => '订单商品数量',
            'shipping_status' => '发货状态',
            'freight' => '运费',
            'shipping_time' => '发货时间',
            'transaction_id' => '第三方平台交易流水号',
            'user_remark' => '用户备注',
            'confirm_take_time' => '确认收货时间',
            'cancel_time' => '订单取消时间',
            'refund_status' => '退款状态',
            'order_remarks' => '订单备注',
            'del' => '删除 1-删除 0-未删除',
            'create_time' => '下单时间',
            'update_time' => '修改时间',
            'transaction_info' => '第三方平台信息',
            'express_type' => '快递类型',
            'express_sn' => '快递单号',
            'party_order' => '第三方订单号',
            'is_comment' => '是否评价完',
        ];
    }
    public function getGoods()
    {
        return $this->hasMany(OrderGoods::className(),['order_id'=>'id']);
    }
    /**
     * 创建订单号
     * @return mixed|string
     */
    public static function makeOrderid()
    {
        $orderId = time() . '' . rand(1000, 9999);
        if (self::find()->where(['order_sn' => $orderId])->exists()) {
            $orderId = self::makeOrderid();
        }
        return $orderId;
    }
    /**
     * 创建订单号
     * @return mixed|string
     */
    public static function makePartyOrder($mark='wx')
    {
        $orderId = $mark.'_'.time() . '' . rand(1000, 9999);
        if (self::find()->where(['party_order' => $orderId])->exists()) {
            $orderId = self::makeOrderid();
        }
        return $orderId;
    }

    /**
     * 计算金额
     * @param array $goods
     * @param $userid
     * @return array
     */
    public static function calculate(array $goods,$userid,$is_cart=0)
    {
        $huiyuan = false;
        $shop_discount = System::getModel()->shop_discount??0;
        if ($shop_discount>0){
            $huiyuan = (new User())->isHuiyuan($userid,'','',0);
        }
        foreach ($goods as &$good){
            if (empty($good['g_id'])){
                return commonApi::message('商品编号不存在',false);
            }
            if (empty($good['spec_id'])){
                return commonApi::message('规格编号不存在',false);
            }
            if (empty($good['num'])){
                return commonApi::message('请选择购买数量',false);
            }
            if (!preg_match("/^[1-9][0-9]*$/" ,$good['num'])){
                return commonApi::message('购买数量必须是整数',false);
            }
            $good['mark'] = $good['g_id'].'_'.$good['spec_id'];
        }
        $markArr = array_column($goods,null,'mark');
        $goods_id = array_column($goods,'g_id');
        $spec_id = array_column($goods,'spec_id');
        $d = Goods::find()
            ->where(['id'=>$goods_id,'delete'=>0])
            ->with([
                'spec' => function ($query)use($spec_id){
                    $query->where(['id'=>$spec_id]);
                }
            ])
            ->asArray()->all();
        $goods_data = [
            'total_amount'=>0,//商品总价
            'discount_amount'=>0,//优惠金额
            'freight'=>0,//运费
            'pay_amount'=>0,//支付金额
            'total_num'=>0,//总数
        ];
        $goods_spec = [];
        $goods_name = [];
        foreach ($d as $value){
            $goods_name[] = $value['name'];
            foreach ($value['spec'] as $item){
                $mark = $value['id'].'_'.$item['id'];
                $num = $markArr[$mark]['num'];
                if ($num>$item['stock']){
                    if (!$is_cart){
                        return commonApi::message('库存不足',false);
                    }else{
                        continue;
                    }
                }
                $goods_data['total_num'] += $num;
                $price = $item['price']*$num;
                $goods_data['total_amount'] += $price;

                $pay = $price;
                if ($huiyuan){
                    $pay = $price*($shop_discount/10);
                }
                $discount = bcsub($price,$pay,2);
                $goods_data['discount_amount'] = $discount;
                $goods_data['pay_amount'] = $pay;
                unset($value['details']);
                $one = [
                    'good_id'=>$value['id'],
                    'spec_id'=>$item['id'],
                    'good_name'=>$value['name'],
                    'good_num'=>$num,
                    'good_price'=>$value['price'],
                    'total_price'=>$price,
                    'total_pay_price'=>$pay,
                    'discount_price'=>$discount,
                    'spec_info'=>json_encode($item),
                    'spec_name'=>$item['name'],
                    'good_info'=>json_encode($value),
                ];
                if ($is_cart){
                    $one['main_img'] = $value['main_img'];
                    $one['stock'] = $item['stock'];
                    $one['mark'] = $mark;
                }
                $goods_spec[] = $one;
            }
        }
        $data = [
            'goods_data'=>$goods_data,
            'goods_spec'=>$goods_spec,
            'goods_name'=>$goods_name,
        ];
        return commonApi::message('成功',true,$data);
    }

    /**
     * 生成支付参数
     * @param $amount 金额
     * @param $userid 用户id
     * @param $order_sn 订单号
     * @param $desc 描述
     * @return array
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public static function getPayresponse($amount,$userid,$order_sn,$desc)
    {
        if ($amount<=0){
            return commonApi::message('支付成功',true,['is_pay'=>0]);
        }
        $openid = User::find()->where(['id'=>$userid])->select(['openid'])->scalar();
        if (!$openid){
            return commonApi::message('请授权微信！',false);
        }
        $system = System::getModel();
        if (!$system->mch_id||!$system->pay_key||!$system->a_appid){
            return commonApi::message('请设置微信支付参数！',false);
        }
        $config = [
            'app_id' => $system->a_appid,
            'mch_id' => $system->mch_id,
            'key' => $system->pay_key,
            'notify_url' => Yii::$app->request->hostInfo.'/api/pay-notify/order'
        ];
        try {
            $app = Factory::payment($config);
            $result = $app->order->unify([
                'body' => $desc,
                'out_trade_no' => $order_sn,
                'total_fee' => $amount*100,
                'trade_type' => 'JSAPI',
                'openid' => $openid,
            ]);
            if ($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS' && isset($result['prepay_id'])){
                $config = $app->jssdk->bridgeConfig($result['prepay_id'], false); // 返回数组
                $config['is_pay'] = 1;
                return commonApi::message('等待支付',true,$config);
            }
            $ms = empty($result['err_code_des'])?$result['return_msg']:$result['err_code_des'];
            throw new \Exception($ms);
        }catch (\Exception $e){
            return commonApi::message($e->getMessage(),false);
        }
    }

    /**
     * 保存订单参数
     * @param $pay 支付参数
     * @param $calculate 计算参数
     * @param $userid 用户id
     * @param $order_sn 订单号
     * @param $party_order 微信订单号
     * @param $address 地址
     * @return array
     */
    public function saveOrder($pay,$calculate,$userid,$order_sn,$party_order,$address)
    {
        $order_cancel = System::getModel()->order_cancel;
        $order_cancel = $order_cancel??0;
        $time = date('Y-m-d H:i:s');
        $tran = Yii::$app->db->beginTransaction();
        try {
            $order = new self();
            $order->userid = $userid;
            $order->order_sn = $order_sn;
            $order->order_status = $pay['is_pay']?0:1;
            $order->pay_status = $pay['is_pay']?0:1;
            $order->pay_time = $pay['is_pay']?'':$time;
            $order->total_amount = $calculate['goods_data']['total_amount'];
            $order->pay_amount = $calculate['goods_data']['pay_amount'];
            $order->discount_amount = $calculate['goods_data']['discount_amount'];
            $order->total_num = $calculate['goods_data']['total_num'];
            $order->freight = $calculate['goods_data']['freight'];
            $order->party_order = $party_order;
            $order->consignee = $address['consignee'];
            $order->province = $address['province'];
            $order->city = $address['city'];
            $order->district = $address['district'];
            $order->address = $address['address'];
            $order->mobile = $address['mobile'];
            if ($order->save()){
                $up = [];
                $up_id = [];
                foreach ($calculate['goods_spec'] as &$value){
                    $value['order_id'] = $order->id;
                    $value['create_time'] = $time;
                    $value['update_time'] = $time;
                    $num = $value['good_num'];
                    $up[] = [
                        'surplus'=>"`surplus`-$num"
                    ];
                    $up_id[] = $value['spec_id'];
                }
                if ($up){
                    $sql = TransformApi::batchUpdate(GoodsSpec::getTableSchema()->name,$up,$up_id);
                    \Yii::$app->db->createCommand($sql)->execute();
                }
                $field = array_keys($calculate['goods_spec'][0]);
                $res = (new OrderGoods())->insertAll($field,$calculate['goods_spec']);
                if ($res){
                    if ($order_cancel>0&&$order->pay_status==0){
                        Yii::$app->queue->delay($order_cancel*60)->push(new OrderBehavior([
                            'method' => OrderBehavior::ORDER_CANCEL,
                            'params' => ['id'=>$order->id],
                        ]));
                    }
                    $tran->commit();
                    return commonApi::message('下单成功等待支付');
                }
                throw new Exception('下单失败！');
            }
            throw new Exception(commonApi::getModelError($order));
        }catch (\Exception $e){
            $tran->rollBack();
            return commonApi::message($e->getMessage(),false);
        }
    }

    /**
     * 支付回调
     * @param $message
     * @return bool
     * @throws \yii\base\InvalidConfigException
     * @throws \yii\db\Exception
     */
    public function payCallback($message)
    {
        if (empty($message['out_trade_no'])){
            return true;
        }
        $order = Order::find()->where(['party_order'=>$message['out_trade_no']])->one();
        if (!$order || $order->pay_status!==0 || $order->order_status!==0) {
            return true;
        }
        if ($message['return_code'] === 'SUCCESS') { // return_code 表示通信状态，不代表支付状态
            // 用户是否支付成功
            if ($message['result_code'] === 'SUCCESS') {
                $order->pay_time = date('Y-m-d H:i:s'); // 支付时间
                $order->pay_status = 1; // 支付状态
                $order->order_status = 1; // 订单状态
                //增加用户累计消费
                User::updateAllCounters(['total_order_amount'=>$order->pay_amount],['id'=>$order->userid]);
                //增加商品销量

                //增加商品销量
                $orderGoods = OrderGoods::find()
                    ->where(['order_id'=>$order->id])
                    ->select(['good_id','sum(good_num) as good_num'])
                    ->groupBy(['good_id'])
                    ->asArray()->all();
                $update = [];
                $update_id = [];
                foreach ($orderGoods as $good){
                    $value = $good['good_num'];
                    $update[] = [
                        'sales_volume'=>"`sales_volume`+$value"
                    ];
                    $update_id[] = $good['good_id'];
                }
                $spec = OrderGoods::find()
                    ->where(['order_id'=>$order->id])
                    ->select(['spec_id','sum(good_num) as good_num'])
                    ->groupBy(['spec_id'])
                    ->asArray()->all();
                $specupdate = [];
                $specupdate_id = [];
                foreach ($spec as $val){
                    $valu = $val['good_num'];
                    $specupdate[] = [
                        'sales_volume'=>"`sales_volume`+$valu"
                    ];
                    $specupdate_id[] = $good['spec_id'];
                }
                if ($update){
                    $sql = TransformApi::batchUpdate(Goods::getTableSchema()->name,$update,$update_id);
                    Yii::$app->db->createCommand($sql)->execute();
                    $sql = TransformApi::batchUpdate(GoodsSpec::getTableSchema()->name,$specupdate,$specupdate_id);
                    Yii::$app->db->createCommand($sql)->execute();
                }
                OrderLog::addLog(0,$order->id,'用户支付成功','用户支付成功',3);
                // 用户支付失败
            } elseif ($message['result_code'] === 'FAIL') {
                $order->order_status = 4;
                OrderLog::addLog(0,$order->id,'用户支付失败','用户支付失败',3);
            }
        } else {
            OrderLog::addLog(0,$order->id,'用户支付失败！！','用户支付失败！！',3);
            return false;
        }
        $order->transaction_info = json_encode($message);
        $order->save(); // 保存订单
        return true;
    }


    /**
     * 获取营销数据
     * @param $start 开始时间
     * @param $end 结束时间
     * @param string $business_id 商家id
     * @return array|\yii\db\ActiveRecord|null
     */
    public static function getMarketData($start,$end,$userid='')
    {
        $data = Order::find()
            ->where(['pay_status'=>[1,2,3]])
            ->andFilterWhere(['userid'=>$userid])
            ->andFilterWhere(['between','pay_time',$start,$end])
            ->select(['sum(pay_amount) as order_amount','count(id) as number'])
            ->asArray()
            ->one();
        $data['order_amount'] = $data['order_amount']??0;
        $data['number'] = $data['number']??0;
        return $data;
    }
}
